<template>
  <div class="m-docx-preview">
    <div class="docx-preview__container" ref="docxContainerRef"></div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import axios from 'axios'
import Pizzip from 'pizzip'
import Docxtemplater from 'docxtemplater'
import { renderAsync } from 'docx-preview'
import { saveAs } from 'file-saver'

defineOptions({
  name: 'MDocxPreview'
})

// 加载文件 => arraybuffer
const loadFile = (url: string) => {
  return axios
    .request({
      url,
      responseType: 'arraybuffer'
    })
    .then((res) => {
      return res.data
    })
}

// arraybuffer => blob
const setData = (arraybuffer: ArrayBuffer, data?: Record<string, any>) => {
  // 创建一个PizZip实例，内容为模板的内容
  const zip = new Pizzip(arraybuffer)
  // 创建并加载docxtemplater实例对象
  const doc = new Docxtemplater().loadZip(zip)

  // 设置模板变量的值
  if (data) {
    // 去除未定义值所显示的undefined
    doc.setOptions({
      nullGetter: () => ''
    })
    // 设置模板变量的值
    doc.setData(data)
    // 用模板变量的值替换所有模板变量
    doc.render()
  }

  // 生成一个代表docxtemplater对象的zip文件（不是一个真实的文件，而是在内存中的表示）
  let outBlob = doc.getZip().generate({
    type: 'blob',
    mimeType:
      'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
  })

  return outBlob
}

// docx 预览
const docxContainerRef = ref()
const docxPreview = (url: string, data?: Record<string, any>) => {
  loadFile(url).then((content) => {
    if (!docxContainerRef.value) return
    renderAsync(setData(content, data), docxContainerRef.value)
  })
}

// 导出文件
const docxExport = (
  url: string,
  data?: Record<string, any>,
  filename = 'output.docx'
) => {
  loadFile(url).then((content) => {
    saveAs(setData(content, data), filename)
  })
}

defineExpose({
  docxPreview,
  docxExport
})
</script>

<style lang="scss" scoped>
.m-docx-preview {
  min-height: 200px;
  height: 100%;
  border: 2px solid #e4e4e4;
  &__container {
    height: 100%;
    overflow: auto;
  }
}
</style>
